package common

import (
	"encoding/hex"
	"fmt"
	"strconv"

	"github.com/spf13/pflag"
	"hundsun.com/hsl/hschain/protos"
)

// ValidatorType validator type
type ValidatorType int

const (
	// NotNil validator not nil
	NotNil ValidatorType = iota
	// Address validator address format
	Address
)

// NewValidator new validator
func NewValidator(validatorType ValidatorType) Validator {
	switch validatorType {
	case NotNil:
		return &NotNilValidator{}
	case Address:
		return &AddressValidator{}
	}
	return nil
}

// Validator validator interface
type Validator interface {
	Validate(value pflag.Value) error
}

// UnknownValidator unknown validator
type UnknownValidator struct{}

// Validate validate
func (v *UnknownValidator) Validate(val pflag.Value) error {
	return fmt.Errorf("unknown validator")
}

// NotNilValidator not nil validator struct
type NotNilValidator struct{}

// Validate validate not nil
func (v *NotNilValidator) Validate(val pflag.Value) error {
	strVal := val.String()
	switch val.Type() {
	case "uint64":
		uintVal, err := strconv.ParseUint(strVal, 0, 64)
		if err != nil {
			return err
		}

		if uintVal == 0 {
			return fmt.Errorf("value is nil")
		}
		return nil
	case "string":
		if len(strVal) > 0 {
			return nil
		}
		return fmt.Errorf("value is nil")
	case "bytesHex":
		bin, _ := hex.DecodeString(strVal)
		if bin != nil {
			return nil
		}
		return fmt.Errorf("value is nil")
	}
	return fmt.Errorf("unknown value type")
}

// AddressValidator address format validator struct
type AddressValidator struct{}

// Validate validate address
func (v *AddressValidator) Validate(val pflag.Value) error {
	return protos.Address(val.String()).Validate()
}
